package coupon

import (
	sqlc "bp/db/sqlc"
	"bp/internal/util"
	"context"
	"database/sql"
	"fmt"
	"github.com/google/uuid"
	"time"
)

// CreateCouponDistributionParam 新建优惠券投放参数
type CreateCouponDistributionParam struct {
	CreateCouponDistributionParamsPtr *sqlc.CreateCouponDistributionParams
}

// GenerateCouponDistributionBatchNo 生成券投放批次号
func (s *CouponEntityServiceImp) GenerateCouponDistributionBatchNo() string {
	// uuid v1 partI + partIV
	val, _ := uuid.NewUUID()
	vals := util.SplitString(val.String(), "-")
	return fmt.Sprintf("%s%s", vals[0], vals[3])
}

// CreateOrder 新建优惠券
func (s *CouponEntityServiceImp) CreateCouponDistribution(ctx context.Context, q *sqlc.Queries, ptr *CreateCouponDistributionParam) (couponDistrituionPtr *sqlc.CouponDistribution, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	couponDistrituion, err := q.CreateCouponDistribution(ctx, *ptr.CreateCouponDistributionParamsPtr)
	if err != nil {
		return
	}
	slog.Infof("1 CreateCouponDistribution ok")

	couponDistrituionPtr = &couponDistrituion
	return
}

// UpdateCouponDistributionParam 更新优惠券投放参数
type UpdateCouponDistributionParam struct {
	DistributionID  int64
	Issuer          string
	DistributeScene string
	Cnt             int32
	Memo            string
}

// UpdateCouponDistribution 更新优惠券投放
func (s *CouponEntityServiceImp) UpdateCouponDistribution(ctx context.Context, q *sqlc.Queries, ptr *UpdateCouponDistributionParam) (couponDistributionPtr *sqlc.CouponDistribution, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	distributionID := ptr.DistributionID
	couponDistributionPtr, err = s.GetCouponDistributionPtr(ctx, q, distributionID)
	if err != nil {
		return
	}
	slog.Infof("1 GetCouponDistributionPtr ok")

	var couponDistribution sqlc.CouponDistribution
	if couponDistributionPtr.IsExecuted {
		couponDistribution, err = q.UpdateCouponDistributionWithExecuted(ctx, sqlc.UpdateCouponDistributionWithExecutedParams{
			ID:              distributionID,
			Issuer:          ptr.Issuer,
			DistributeScene: ptr.DistributeScene,

			Memo: sqlc.NSFromString(ptr.Memo),
		})
	} else {
		couponDistribution, err = q.UpdateCouponDistributionWithoutExecuted(ctx, sqlc.UpdateCouponDistributionWithoutExecutedParams{
			ID:              distributionID,
			Issuer:          ptr.Issuer,
			DistributeScene: ptr.DistributeScene,
			Cnt:             ptr.Cnt,
			Memo:            sqlc.NSFromString(ptr.Memo),
		})
	}
	if err != nil {
		return
	}
	slog.Infof("2 UpdateCouponDistribution ok")

	couponDistributionPtr = &couponDistribution
	return
}

// ExecuteCouponDistributionParam 执行优惠券投放参数
type ExecuteCouponDistributionParam struct {
	CouponDistributionPtr *sqlc.CouponDistribution
	DistributionID        int64
}

// ExecuteCouponDistribution 执行优惠券投放
func (s *CouponEntityServiceImp) ExecuteCouponDistribution(ctx context.Context, q *sqlc.Queries, ptr *ExecuteCouponDistributionParam) (couponDistributionPtr *sqlc.CouponDistribution, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if ptr.CouponDistributionPtr != nil {
		couponDistributionPtr = ptr.CouponDistributionPtr
	} else {
		couponDistributionPtr, err = s.GetCouponDistributionPtr(ctx, q, ptr.DistributionID)
		if err != nil {
			return
		}
		slog.Infof("0 GetCouponDistributionPtr ok")
	}

	if couponDistributionPtr.IsExecuted {
		err = fmt.Errorf("优惠券投放已执行完成")
		return
	}
	if couponDistributionPtr.IsExecuting {
		err = fmt.Errorf("优惠券投放正在执行")
		return
	}
	distributionID := couponDistributionPtr.ID

	err = q.MarkCouponDistributionExecuting(ctx, distributionID)
	if err != nil {
		return
	}

	s.AsyncBatchCreateCouponDistributionDetail(ctx, &AsyncBatchCreateCouponDistributionDetailParam{
		CouponDistributionPtr: couponDistributionPtr,
	})

	couponDistributionPtr.IsExecuting = true
	return
}

// MarkCouponDistributionParam 标记优惠券投放参数
type MarkCouponDistributionParam struct {
	CouponDistributionPtr *sqlc.CouponDistribution
	DistributionID        int64
}

// MarkCouponDistributionExecuted 标记优惠券投放记录已执行
func (s *CouponEntityServiceImp) MarkCouponDistributionExecuted(ctx context.Context, q *sqlc.Queries, p MarkCouponDistributionParam) (couponDistributionPtr *sqlc.CouponDistribution, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if p.CouponDistributionPtr != nil {
		couponDistributionPtr = p.CouponDistributionPtr
	} else {
		couponDistributionPtr, err = s.GetCouponDistributionPtr(ctx, q, p.DistributionID)
		if err != nil {
			if sql.ErrNoRows == err {
				err = fmt.Errorf("无法找到要标记的优惠券投放记录")
			}
			return
		}
		slog.Infof("0 GetCouponDistributionPtr ok")
	}
	if couponDistributionPtr.IsExecuted {
		err = fmt.Errorf("优惠券投放执行标志已标记")
		return
	}
	distributionID := couponDistributionPtr.ID

	err = q.MarkCouponDistributionExecuted(ctx, distributionID)
	if err != nil {
		return
	}
	couponDistributionPtr.IsExecuted = true
	couponDistributionPtr.Executed = sqlc.NTimeFromTime(time.Now())
	slog.Infof("1 MarkCouponDistributionExecuted ok")

	return
}

// MarkCouponDistributionIsAnyoneGot 标记优惠券投放记录已被任何人领取
func (s *CouponEntityServiceImp) MarkCouponDistributionIsAnyoneGot(ctx context.Context, q *sqlc.Queries, p MarkCouponDistributionParam) (couponDistributionPtr *sqlc.CouponDistribution, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if p.CouponDistributionPtr != nil {
		couponDistributionPtr = p.CouponDistributionPtr
	} else {
		couponDistributionPtr, err = s.GetCouponDistributionPtr(ctx, q, p.DistributionID)
		if err != nil {
			if sql.ErrNoRows == err {
				err = fmt.Errorf("无法找到要标记的优惠券投放记录")
			}
			return
		}
		slog.Infof("0 GetCouponDistributionPtr ok")
	}
	if couponDistributionPtr.IsAnyoneGot {
		err = fmt.Errorf("优惠券投放执行标志已被会员领取")
		return
	}
	distributionID := couponDistributionPtr.ID

	err = q.MarkCouponDistributionIsAnyoneGot(ctx, distributionID)
	if err != nil {
		return
	}
	couponDistributionPtr.IsAnyoneGot = true
	slog.Infof("1 MarkCouponDistributionDistributedToMember ok")

	return
}
